import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, TreeRepository } from 'typeorm';
import { ArticleCategoryEntity } from './article-category.entity';
import { CreateArticleCategoryDto } from './article-category.dto';
import { deleteEmptyChildren, generateRandomValue } from '~/utils';
import { CommonStatus } from '~/common/entity/common.entity';
import { ErrorEnum } from '~/constants/error-code.constant';

@Injectable()
export class ArticleCategoryService {
  constructor(
    @InjectRepository(ArticleCategoryEntity)
    private readonly articleCategoryRepo: TreeRepository<ArticleCategoryEntity>
  ) {}

  async create(
    articleCategory: Partial<ArticleCategoryEntity> & { parentId?: number; tenantId?: number }
  ): Promise<ArticleCategoryEntity> {
    articleCategory.code = generateRandomValue(20);
    let parent = null;
    let tenant = null;
    if (articleCategory.parentId) {
      parent = await this.articleCategoryRepo.findOneBy({ id: articleCategory.parentId });
    }
    if (articleCategory?.tenantId) {
      tenant = { id: articleCategory.tenantId };
    } else {
      throw new BadRequestException(ErrorEnum.NO_TENANT);
    }
    return this.articleCategoryRepo.save({ ...articleCategory, parent, tenant });
  }

  async findAll(): Promise<ArticleCategoryEntity[]> {
    return this.articleCategoryRepo.find();
  }

  async findAllByTenantId(tenantId?: number): Promise<ArticleCategoryEntity[]> {
    if (!tenantId) {
      throw new BadRequestException(ErrorEnum.NO_TENANT);
    }

    const categoriesTree = await this.articleCategoryRepo
      .createQueryBuilder('category')
      .leftJoinAndSelect('category.children', 'children')
      .where('category.status = :status', { status: CommonStatus.YES })
      .andWhere('category.isDeleted = :isDeleted', { isDeleted: CommonStatus.NO })
      .andWhere('category.parentId IS NULL')
      .andWhere('(category.tenant_id = :tenantId OR category.tenant_id IS NULL)', {
        tenantId,
      })
      .select([
        'category.id',
        'category.name',
        'category.code',
        'category.description',
        'children.id',
        'children.name',
        'children.code',
        'children.description',
      ])
      .getMany();

    deleteEmptyChildren(categoriesTree);

    // 为树结构数据的二级添加一个“全部”分类，id为一级的id
    categoriesTree.forEach((item) => {
      if (item.children && item.children.length) {
        item.children.unshift({
          id: item.id,
          name: '全部',
          code: item.code,
          tenant: item.tenant,
          status: item.status,
          createdAt: item.createdAt,
          updatedAt: item.updatedAt,
        } as ArticleCategoryEntity);
      }
    });

    return categoriesTree;
  }

  async findOne(id: number): Promise<ArticleCategoryEntity> {
    return this.articleCategoryRepo.findOneBy({ id });
  }

  async findSomeByIds(ids: number[]): Promise<ArticleCategoryEntity[]> {
    return this.articleCategoryRepo.find({ where: { id: In(ids) } });
  }

  async update(id: number, articleCategory: CreateArticleCategoryDto): Promise<void> {
    await this.articleCategoryRepo.update(id, articleCategory);
  }

  async remove(id: number): Promise<void> {
    await this.articleCategoryRepo.delete(id);
  }
}
